查看原文
其他

网络物理模拟(三):具有确定性的帧同步(下篇)

2016-09-21 翻译:张乾光 Gad-腾讯游戏开发者平台

这还不是全部!随着延迟时间的增大和丢包率的增加,整个情况会变得更加的糟糕。这是在250毫秒延迟和百分之五丢包率的情况下,使用基于TCP协议的确定性的帧同步模型进行相同的仿真模拟运算导致的结果:

https://v.qq.com/txp/iframe/player.html?vid=j1309mtb284&width=500&height=375&auto=0

现在我要承认一个事情,如果延迟时间设置的非常低的话同时不存在丢包的情况下,那么使用TCP协议进行输入信息的传输会是一个非常可以接受的结果。但是请注意,如果你使用TCP协议来发送时间敏感的数据的话,随着延迟时间的增大和丢包率的增加,整个结果会急剧恶化。


我们可以做得更好吗?我们能在自己的游戏里面找到一种比使用TCP协议更好的办法。同时还能实现可信赖的有序传递?


答案是肯定的。但前提是我们需要改变游戏的规则。

下面将具体描述下我们将使用的技巧。我们需要确保所有的输入信息能够可靠地按顺序到达。但是如果我们只发送UDP数据包输入。但是如果我们只使用UDP数据包来发送输入信息的话,这里面的一些数据包会丢失。那么如果我们不采用事后检测的方法来判断哪些数据包丢失并发送这些丢失的数据包的话,我们采用另外一种方法,只是把我们有的所有输入信息都冗余的发送直到我们知道这些输入信息成功的到达另外一侧怎么样?

输入信息都非常非常的小(只有6比特这么大)。让我们假设下我们在每秒需要发送60个输入信息(因为模拟仿真的频率是60fps ),而且我们知道一个往返的时间大概是在30毫秒到250毫秒之间。纯粹为了好玩,让我们假设下载最糟糕的情况下,一个往返的时间可以高达2秒,如果出现这种情况的话,那么整个连接就会超时。这意味着在平均情况我们只需要包括大概215帧的输入信息,而在最坏情况下,我们大概需要120帧的输入信息。那么最坏情况下,输入信息的大小是120*6 = 720比特。这只是90字节的输入信息!这是安全合理的。

我们还能做的更好。在每一帧中都出现输入信息的变化是非常不常见的。如果我们不是从最近有输入发生的那一帧开始计数来发送我们的数据包,而是从第一个输入信息的6比特开始,并且加上所有未打包的输入信息的数目。这样,当我们对这些输入信息进行遍历将它们写入数据包的时候,如果发现这一帧的输入信息如果和之前帧的输入信息不同的话,我们可以写入一个单独的比特位(1),如果发现这一帧的输入信息如果和之前帧的输入信息相同的话,我们可以写入一个单独的比特位(0)。所以这一帧的输入信息如果和之前帧的输入信息不同的话,我们需要写入7个比特位(这种情况很少见),这一帧的输入信息如果和之前帧的输入信息相同的话,我们只需要写入1个比特位(这种情况其实非常常见)。在输入信息很少发生变化的情况,这是一个重大的胜利,而在最坏的情况下出现的情况也不会非常糟糕。只需要发送额外120个比特的数据,也就是说在最坏情况下,也只有15字节的额外开销

当然在这种情况下,需要从右边的模拟仿真中发送一个数据包到左边的模拟仿真中去,这样左边的模拟仿真才知道哪些输入信息被成功收到了。在每一帧,右边的模拟仿真都会从网络中读取输入的数据包,然后才会把这些数据包添加到延迟播放缓冲区,并且通过帧号记录它已经收到的最近那一帧的输入信息,或者如果你想容易一点处理这个问题的话,那么使用一个16比特的序列号就能很好的包装这个信息。在所有的输入数据包都被处理以后,如果右边的模拟仿真收到任何帧的输入信息以后都会回复一个数据包给左边的模拟仿真,告诉它最近收到的最新序列号是多少,这基本就是一个“ack”包,也就是确认包。

当左边的模拟仿真收到这个“ack”包,也就是确认包以后,它会滑动输入信息窗口并且丢弃比已经确认的序列号还老的输入信息包。已经没有必要再发送这些输入信息包给右边的模拟仿真了,因为已经知道右边的模拟仿真成功的接受到了这些输入信息包。通过这种方式,我们通常只有少量的输入信息正在传输过程中,而且这个数量还是与数据包的往返时间成正比的。

我们通过改变游戏的规则成功了找到了一种比TCP协议更好的办法。我们并不是通过在UDP协议纸上构建了实现TCP协议百分之九五功能的新协议,而是实现了一种非常不同的方法,而且更加适合我们的要求:数据对时间非常敏感。我们开发了一个自定义的协议,可以冗余的发送所有未被确认的输入信息,这样就可以在不降低同步质量的情况下处理延迟时间和丢包的问题。


所以这种方法到底比通过TCP协议来发送数据好多少呢?
让我们通过一个例子来看一下


https://v.qq.com/txp/iframe/player.html?vid=r13095uzru8&width=500&height=375&auto=0

上面的视频是基于UDP协议来使用具有确定性的帧同步模型,延迟时间是2秒,并且有百分之二十五的丢包率。事实上,如果我仅仅把播放延迟缓冲区的缓冲时间从100毫秒增大到250毫秒,我就能让整个模拟仿真在百分之五十丢包率的情况平滑的运行。想象下如果我们是使用基于TCP协议的具有确定性的帧同步模型,我们该看到多么可怕的场景!

所以最后我们能得到这么一个结论:即使这是一个TCP协议最具有优势的情况下,这是整个系列里面唯一一个依赖可靠性、有序性数据传输的网络模型,我们还是可以很容易的通过一个自定义的协议基于UDP来发送我们的数据包,并且得到的效果更好。

【版权声明】

原文作者未做权利声明,视为共享知识产权进入公共领域,自动获得授权。



点击一下立即阅读相关好文章


设计师如何避免沦为美工MMORPG游戏开始衰落了?


让人惊艳的黑科技程序员跨界还可以做什么


这么做设计才好玩守望先锋为什么好玩


人民币玩家一样会被吊打


......




近期热文

网络物理模拟(三):具有确定性的帧同步(上篇)

Linux 内核设计模式(一)


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存